home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 22
/
Mac Magazin and MacEasy Magazine CD - Issue 22.iso
/
System
/
Systemerweiterungen
/
NoPowerOffKey 1.2
/
PatchPowerOff.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-09
|
6KB
|
212 lines
/*
** Apple Macintosh Developer Technical Support
**
** Sample code demonstrating how to patch PowerOff key
**
** by Brian Bechtel, Apple Developer Technical Support
**
** File: PatchPowerOff.c
**
** Copyright © 1995 Apple Computer, Inc.
** All rights reserved.
**
** You may incorporate this sample code into your applications without
** restriction, though the sample code has been provided "AS IS" and the
** responsibility for its operation is 100% yours. However, what you are
** not permitted to do is to redistribute the source as "DTS Sample Code"
** after having made changes. If you're going to re-distribute the source,
** we require that you make it clear in the source that the code was
** descended from Apple Sample Code, but that you've made changes.
*/
#include <Gestalt.h>
#include <Resources.h>
#include <Errors.h>
#include <OSUtils.h>
#include <Traps.h>
#include <SetupA4.h>
#include <A4Stuff.h>
/* from technote 1017, "System 7.5.3" Thanks to John Montbriand for pointing
* out that I'd used a seed release of the technote, which didn't include in
* the UPP definition any space for the result of the call.
*/
#ifdef PowerPC
enum {
uppPowerOffProcInfo = kPascalStackBased
| RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) /* space for result */
| STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
| STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
};
#endif
/* constants used as parameters to the power off key routine */
enum {
kPowerKey = 0x7F,
kDissablePwKy = 0x6B,
kEnablePwKy = 0x00,
kShutdownDlog = 0x7E,
kNoDismiss = 0x00,
kOneSecond = 0x70,
kTenSeconds = 0x400
};
/* declaration for the power off key routine */
typedef pascal OSErr (*PwrKeyProc)(short item, short action);
/* for debugging */
#define assert(i) if ((i) DebugStr("\p;printf \"assertion failed file %s line %d\" __FILE__, __LINE__")
#define kINITid 0 /* matches the resID in the 68K Project preferences */
#define kICONid 128
pascal void ShowIcon7(short iconId, Boolean advance);
// local function declarations
void InitAlertPatch(void);
void ClearAlertPatch(void);
void asm AlertPatch(void);
OSErr DisablePowerOffKey(void);
void main(void);
static long gOriginalTrapPtr = 0;
static Boolean gAlertPatchIsInstalled = false;
/*
* InstallAlertPatch
* This routine patches the Alert() trap so that we can check for
* the PowerOff alert and dismiss it before it comes up.
*/
void InitAlertPatch(void)
{
if (gAlertPatchIsInstalled == false)
{
gOriginalTrapPtr = (long) NGetTrapAddress( _Alert, ToolTrap);
NSetTrapAddress( (UniversalProcPtr)(AlertPatch), _Alert, ToolTrap);
gAlertPatchIsInstalled = true;
}
}
/*
* ClearAlertPatch
* This routine clears out the patch we installed in InstallAlertPatch.
* Note: Never call this routine from within an extension; you don't know
* what other patches may have been put on Alert() after you installed
* your patch, and bad things would happen if you eliminate yourself from
* the chain of patches...
*/
void ClearAlertPatch(void)
{
if (gAlertPatchIsInstalled == true)
{
NSetTrapAddress( (UniversalProcPtr)(gOriginalTrapPtr), _Alert, ToolTrap);
gAlertPatchIsInstalled = false;
}
}
/*
* AlertPatch
* This patch checks to see if we are about to display alert -16500. This
* is the ALRT id used by the dialog which asks if you want to shutdown, etc.
* If we are about to show that dialog, fake things up as if we have already
* shown the dialog, and the user has pressed the Cancel button. The result
* is that the dialog is never shown, and no action is taken. Just as if
* the PowerOff code was never added to the system...
* Call this routine only if the programmatic method (using the 'pwky' Gestalt
* selector) fails.
* This patch trashes register a0 and possibly register d0, but
* these registers are trashed by Alert anyway.
*/
void asm AlertPatch(void)
{
// Check for proper alert. If it's the trap we want to avoid,
// return to caller without actually executing the Alert trap.
// Set up the stack so it looks as if the user hit okay.
PatchPowerOff:
// test for specific PowerOff dialog id. If we find it, return as if we hit cancel.
cmpi.w #-16500,8(sp) // we want to avoid -16500
bne exitPatchPowerOff
// if it's the alert we want, return to caller without
// executing the alert.
// FUNCTION Alert ( alertID: INTEGER; filterProc: ProcPtr) : INTEGER;
// means that the stack looks like this:
// sp + 0 -> return address (4 bytes)
// + 4 -> filterProc (4 bytes)
// + 8 -> alertID (2 bytes)
movea.l (sp)+, a0 // the caller's return address
lea 6(sp), sp // clear off the parms put on by caller
move.w #2, (sp) // tell the system we hit cancel. (2nd button = cancel)
jmp (a0) // return to caller without actually calling Alert
exitPatchPowerOff:
// call the original trap.
//First, set up a4 to access the old trap address
jsr SetUpA4 // puts old a4 into register d0
lea gOriginalTrapPtr, a0
exg d0, a4 // restore old value of a4
movea.l (a0), a0
jmp (a0)
}
/*
* DisablePowerOffKey
* This routine will either call the routine pointed to by the Gestalt
* selector 'pwky', telling it to disable the power off key, or this
* routine will return an error (usually telling you the Gestalt selector
* is not installed.)
*/
OSErr DisablePowerOffKey(void)
{
OSErr err;
PwrKeyProc pPwrKey;
err = Gestalt('pwky', (long*) &pPwrKey);
if ( (long) pPwrKey == nil )
err = gestaltUndefSelectorErr; // no proc ptr means no selector
if ( err == noErr )
#ifdef PowerPC
err = CallUniversalProc((UniversalProcPtr) pPwrKey,
uppPowerOffProcInfo, kPowerKey, kDissablePwKy);
#else
err = pPwrKey(kPowerKey, kDissablePwKy);
#endif
return err;
}
/* main */
void main(void)
{
long oldA4;
Handle h;
OSErr err = noErr;
#ifdef USE_DEBUGGER_CALLS
Debugger();
#endif
/* set up our A4 context for _this file_ */
oldA4 = SetCurrentA4();
RememberA4();
/* First try to disable the power key programmatically.
* If that doesn't work, do a skanky hack.
*/
if (DisablePowerOffKey() != noErr)
{
/* detach ourselves */
h = Get1Resource('INIT', kINITid);
if (h) DetachResource(h);
InitAlertPatch();
}
ShowIcon7(kICONid, true);
/* restore the a4 world */
SetA4(oldA4);
}